page.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. 'use client';
  2. import './style.scss';
  3. import '../../crew/widget/style.scss';
  4. import { useState, useEffect, useCallback } from 'react';
  5. import { useParams } from 'next/navigation';
  6. import Link from 'next/link';
  7. import { fetchApi } from '@/lib/utils/client';
  8. import { useStudioContext } from '@/app/studio/context';
  9. import type { CrewItem, CrewListResponse } from '@/types/response/crew/list';
  10. import { Button } from '@/components/ui/button';
  11. import CrewSettingsTab from './_components/CrewSettingsTab';
  12. import CrewMembersTab from './_components/CrewMembersTab';
  13. import CrewWidgetTab from './_components/CrewWidgetTab';
  14. import CrewSessionTab from './_components/CrewSessionTab';
  15. const TABS = [
  16. { key: 'settings', label: '기본 설정' },
  17. { key: 'members', label: '크루원' },
  18. { key: 'widget', label: '위젯' },
  19. { key: 'session', label: '세션' }
  20. ] as const;
  21. type TabKey = typeof TABS[number]['key'];
  22. export default function CrewDetailPage()
  23. {
  24. const { id } = useParams<{ id: string }>();
  25. const { channelID } = useStudioContext();
  26. const crewID = Number(id);
  27. const [crew, setCrew] = useState<CrewItem|null>(null);
  28. const [loading, setLoading] = useState(true);
  29. const [activeTab, setActiveTab] = useState<TabKey>('members');
  30. const fetchCrew = useCallback(async () => {
  31. if (!channelID) return;
  32. try {
  33. const res = await fetchApi<CrewListResponse>(`/api/studio/crew/list/${channelID}`);
  34. const found = res.data?.list.find(c => c.id === crewID);
  35. if (found) setCrew(found);
  36. } catch {}
  37. }, [channelID, crewID]);
  38. useEffect(() => {
  39. setLoading(true);
  40. fetchCrew().finally(() => setLoading(false));
  41. }, [fetchCrew]);
  42. if (loading) {
  43. return <div className="studio-page"><p className="studio-page__empty">준비 중...</p></div>;
  44. }
  45. if (!crew) {
  46. return <div className="studio-page"><p className="studio-page__empty">크루를 찾을 수 없습니다.</p></div>;
  47. }
  48. return (
  49. <div className="studio-page crew-detail">
  50. {/* 헤더: 제목 + 액션 버튼 */}
  51. <div className="crew-detail__header">
  52. <div className="crew-detail__info">
  53. <h1 className="crew-detail__title">{crew.name}</h1>
  54. {crew.description && <p className="crew-detail__desc">{crew.description}</p>}
  55. </div>
  56. <div className="crew-detail__actions">
  57. <Button variant="outline" size="sm" asChild>
  58. <Link href="/studio/donation/crew">< 목록으로</Link>
  59. </Button>
  60. </div>
  61. </div>
  62. {/* 탭 네비게이션 */}
  63. <nav className="crew-tabs">
  64. {TABS.map(tab => (
  65. <button
  66. type="button"
  67. key={tab.key}
  68. className={`crew-tabs__item${activeTab === tab.key ? ' crew-tabs__item--active' : ''}`}
  69. onClick={() => setActiveTab(tab.key)}
  70. >
  71. {tab.label}
  72. </button>
  73. ))}
  74. </nav>
  75. {/* 탭 컨텐츠 */}
  76. <div className="crew-tabs__content">
  77. {activeTab === 'settings' && <CrewSettingsTab crew={crew} onUpdated={fetchCrew} />}
  78. {activeTab === 'members' && <CrewMembersTab crewID={crewID} />}
  79. {activeTab === 'widget' && <CrewWidgetTab crewID={crewID} />}
  80. {activeTab === 'session' && <CrewSessionTab crewID={crewID} />}
  81. </div>
  82. </div>
  83. );
  84. }